package com.diors.commons.script;

import java.io.File;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

import javax.tools.Diagnostic;
import javax.tools.DiagnosticCollector;
import javax.tools.JavaCompiler;
import javax.tools.JavaCompiler.CompilationTask;
import javax.tools.JavaFileObject;
import javax.tools.StandardJavaFileManager;
import javax.tools.ToolProvider;

import org.apache.log4j.Logger;

/**
 * 脚本引擎
 * @author	darren.ouyang <ouyang.darren@gmail.com>
 * @date	2013-10-16
 * @version 1.0
 * @copyright Copyright (c) 2013, darren.ouyang
 */
class ScriptEngline 
{
	private static Logger log = Logger.getLogger(ScriptEngline.class);
	
	//private final ScriptClassLoader classLoader;	//类加载器
	private final JavaCompiler compiler;			//编译器
	private final Iterable<String> options;			//编译选项
	
	private final static String binDir = "bin";
	private final static String srcDir = "script";

	ScriptEngline ()
	{
		compiler = ToolProvider.getSystemJavaCompiler();
		//classLoader = getClass().getClassLoader();
		//classLoader = ClassLoader.getSystemClassLoader();
		//classLoader = new ScriptClassLoader(binDir);
		options = Arrays.asList("-encoding", "UTF-8", "-d", binDir, "-sourcepath", srcDir);
		if (compiler == null) 
		{
			throw new IllegalStateException("系统java编译器无法找到，请确认" +
					"类路径中已经包含tools.jar（注：JDK 6中默认自带，JRE 6中默认不带）。");
		}
	}
	
	
	List<Class<?>> compilePath (String filePath)
	{
		// 获取标准文件管理器实例
		StandardJavaFileManager fileManager = compiler.getStandardFileManager(null, null, null);
		
		// 得到filePath目录下的所有java源文件
		File sourceFile = new File(filePath);
		List<File> sourceFileList = new ArrayList<File>();
		ScriptUtil.getSourceFiles(sourceFile, sourceFileList);
		
		// 没有java文件，直接返回
		if (sourceFileList.size() == 0) 
		{
			log.warn(filePath + "目录下查找不到任何java文件");
			return new ArrayList<Class<?>>();
		}
		
		// 获取要编译的编译单元
		DiagnosticCollector<JavaFileObject> diagnostics = new DiagnosticCollector<JavaFileObject>();
		Iterable<? extends JavaFileObject> compilationUnits = fileManager.getJavaFileObjectsFromFiles(sourceFileList);
		CompilationTask compilationTask = compiler.getTask(null, fileManager, diagnostics, options, null, compilationUnits);
		boolean result = compilationTask.call();
		
		/* 编译结果 */
		if (result)
			log.info(filePath + "编译完毕！");
		else
			errorLog(filePath + "编译失败", diagnostics);
		
		List<Class<?>> list = new ArrayList<Class<?>>();
		for (File file : sourceFileList)
		{
			String className = ScriptUtil.getClassName(filePath, file);
			Class<?> clz = loadClass(className);
			if (clz != null)
				list.add(clz);
		}
		
		return list;
	}
	
	/**
	 * 错误日志
	 * @param info
	 * @param diagnostics
	 * @create	2013-10-16	darren.ouyang
	 */
	private void errorLog (String info, DiagnosticCollector<JavaFileObject> diagnostics)
	{
		if (diagnostics == null)
		{
			log.warn(info);
			return;
		}
		
		for (Diagnostic<? extends JavaFileObject> diagnostic : diagnostics.getDiagnostics()) 
		{
			log.warn(new StringBuilder(info).append("    -- sourceName:").append(diagnostic.getSource().getName()).
					append(",kind:").append(diagnostic.getKind()).append(",LineNumber:").
					append(diagnostic.getLineNumber()).append(",ColumnNumber:").append(diagnostic.getColumnNumber()).
					append(",Msg:").append(diagnostic.getMessage(null)));
		}
	}
	
	/**
	 * 加载class
	 * @param qualifiedClassName
	 * @return
	 * @create	2013-10-16	darren.ouyang
	 */
	private Class<?> loadClass(final String qualifiedClassName)
	{
		Class<?> clz;
		try {
			//clz = classLoader.loadClass(qualifiedClassName);
			//clz = classLoader.loadScriptClass(qualifiedClassName);
			clz = new ScriptClassLoader(binDir).loadScriptClass(qualifiedClassName);
			return clz;
		} catch (ClassNotFoundException e) 
		{
			log.error("加载Class["+ qualifiedClassName +"]失败", e);
		}
		
		return null;
	}
	
}
